/*
 * CTexture.cpp
 *
 *  Created on: Sep 5, 2011
 *      Author: welcome
 */

#include "CTexture.h"

namespace GGEngine {

#define CHECK_ERROR_RETURN(error, message) \
    if (error) {\
        kdLogMessage(message); \
        return -1; \
    }\

CTexture::CTexture() :
		width(0), height(0), pixelData(0), format(0) {
}
GLvoid CTexture::reset() {
	if (pixelData)
		delete[] pixelData;
	width = 0;
	height = 0;
	pixelData = 0;
	format = 0;
}
CTexture::~CTexture() {
	reset();
}

/* This function reads a png file from a file using stdio */
KDint CTexture::ReadPngFile(const KDchar* aFilename) {
	KDchar png_header[8];
	/* open file and test for it being a png */
	FILE *file = fopen(aFilename, "rb");

	CHECK_ERROR_RETURN(!file, "ReadPngFile: File not found!");

	fread(png_header, 1, 8, file);

	if (!png_check_sig((unsigned char *) png_header, 8)) {
		fclose(file);
		return -1;
	}

	/* initialize structures for reading a png file */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	CHECK_ERROR_RETURN(!png_ptr, "ReadPngFile: png_create_read_struct failed");

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr) {
		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
		fclose(file);
		return -1; /* out of memory */
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		fclose(file);
		return -1;
	}

	png_init_io(png_ptr, file);
	png_set_sig_bytes(png_ptr, 8);

	png_read_info(png_ptr, info_ptr);

    width 		= info_ptr->width;
    height 		= info_ptr->height;
    color_type 	= info_ptr->color_type;
    bit_depth 	= info_ptr->bit_depth;

	channels = info_ptr->channels;

	png_read_update_info(png_ptr, info_ptr);

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        fclose(file);
        return -1;
    }
	/* Rowsize in bytes. */

	if ((pixelData = (png_bytep*) kdMalloc(height * sizeof(png_bytep)))
			== NULL) {
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return -1;
	}
	/* set the individual row_pointers to point at the correct offsets */
	for (KDuint i = 0; i < height; ++i){
		pixelData[i] = (png_bytep)kdMalloc(info_ptr->rowbytes);
        CHECK_ERROR_RETURN(!pixelData[i], "ReadPngFile: Out of memory");
	}
	/* now we can go ahead and just read the whole image */
	png_read_image(png_ptr, pixelData);
	/* Clean up. */
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(file);
	return 0;
}
KDint CTexture::loadTexture(const KDchar* filename, ExtType type) {

	CHECK_ERROR_RETURN((type >= UNKNOWN_TYPE),"Unsupported file type.");

	KDint ret = 0;

	// reset the texture
	reset();

	// check, if we have a valid pointer
	CHECK_ERROR_RETURN(!filename, "File name should not be null.");

	ret = ReadPngFile(filename);

	CHECK_ERROR_RETURN(ret, "Can not open PNG file.");

	switch (channels) {

	case 1:
		format = GL_LUMINANCE;
		break;
	case 2:
		format = GL_LUMINANCE_ALPHA;
		break;
	case 3:
		format = GL_RGB;
		break;
	case 4:
		format = GL_RGBA;
		break;
	default:
		format = 0;
		break;
	}
	if (format == 0) {
		reset();
		return -1;
	}
	return 0;
}

} /* namespace GGEngine */
